package com.mrzhou.web.util;

import com.mrzhou.core.tool.utils.JacksonUtil;
import com.mrzhou.core.tool.utils.SpringUtil;
import com.mrzhou.web.props.HttpClientPoolProperties;
import com.mrzhou.web.support.HttpClientConfig;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Http工具类
 */
@Slf4j
public class HttpClientUtil {


    /**
     * 设置编码格式为UTF-8
     */
    private final static String CHARACTER_ENCODING = "UTF-8";

    private final static CloseableHttpClient httpClient = HttpClientUtil.createHttpClient();

    private final static HttpClientPoolProperties prop = SpringUtil.getBeanIgnoreNull(HttpClientPoolProperties.class);

    /**
     * 创建HttpClient客户端
     * 这里使用默认的初始话配置
     */
    private static CloseableHttpClient createHttpClient() {
        if (null == prop) {
            return HttpClientConfig.createHttpClient(new HttpClientPoolProperties());
        }
        return HttpClientConfig.createHttpClient(prop);
    }

    /**
     * 根据URL下载文件
     *
     * @param url
     * @return
     */
    public static InputStream getFile(String url) {
        try {
            HttpGet get = new HttpGet(url);
            CloseableHttpResponse response = httpClient.execute(get);
            return response.getEntity().getContent();
        } catch (IOException e) {
            log.error("{}请求失败： {}", url, e);
        }
        return null;
    }

    /**
     * 发送表单请求
     *
     * @param url
     * @param params
     * @param headers
     * @return
     */
    public static String postFormData(String url, String reqEncoding, Map<String, Object> params, Map<String, String> headers) throws Exception {
        // 创建请求参数队列
        List<NameValuePair> formParams = new ArrayList<>();
        // 处理Map中的请求参数
        if (params != null) {
            formParams = new ArrayList<>();
            for (Map.Entry<String, Object> param : params.entrySet()) {
                NameValuePair pair = new BasicNameValuePair(param.getKey(), String.valueOf(param.getValue()));
                formParams.add(pair);
            }
        }
        UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(formParams, reqEncoding);
        return post(url, uefEntity, headers);
    }

    @SneakyThrows
    public static String postFormData(String url, Map<String, Object> params, Map<String, String> headers) {
        return postFormData(url, CHARACTER_ENCODING, params, headers);
    }

    /**
     * 上传文件
     *
     * @param url
     * @param fileMap
     * @param headers
     * @return
     */
    @SneakyThrows
    public static String postUploadFile(String url, Map<String, Object> fileMap, Map<String, String> headers) {
        log.info("请求: {} 的请求参数: {}, 请求头信息: {}", url, JacksonUtil.toJsonString(fileMap), JacksonUtil.toJsonString(headers));
        if (ObjectUtils.isNotEmpty(fileMap)) {
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            for (Map.Entry<String, Object> entry : fileMap.entrySet()) {
                Object value = entry.getValue();
                if (value instanceof File) {
                    builder.addBinaryBody(entry.getKey(), (File) value);
                } else if (value instanceof MultipartFile) {
                    builder.addBinaryBody(entry.getKey(), ((MultipartFile) value).getInputStream());
                } else {
                    builder.addTextBody(entry.getKey(), String.valueOf(entry.getValue()));
                }
            }
            return post(url, builder.build(), headers);
        }
        throw new RuntimeException("上传文件时, 参数列表不能为空");
    }

    /**
     * 发送POST请求
     */
    public static String post(String url, HttpEntity httpEntity, Map<String, String> headers) {
        try {
            // 创建httpPost
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(httpEntity);

            // 添加header
            if (ObjectUtils.isNotEmpty(headers)) {
                for (Map.Entry<String, String> header : headers.entrySet()) {
                    httpPost.setHeader(header.getKey(), header.getValue());
                }
            }
            CloseableHttpResponse resultResponse = httpClient.execute(httpPost);
            return responseHandler(httpPost, resultResponse);
        } catch (IOException e) {
            log.error("请求:[{}] 失败； 原因：{}", url, e);
        }
        return null;
    }

    /**
     * 发送POST请求, 以JSON形式
     */
    public static String postJson(String url, Object params) {
        StringEntity entity = new StringEntity(JacksonUtil.toJsonString(params), ContentType.APPLICATION_JSON);
        entity.setContentType(ContentType.APPLICATION_JSON.toString());
        return post(url, entity, null);
    }


    /**
     * 发送GET请求
     * 这个方法暂时不要用
     */
    public static String get(String url) {
        try {
            // 创建httpGet
            HttpGet httpGet = new HttpGet(url);
            // 执行get请求.
            CloseableHttpResponse closeResponse = httpClient.execute(httpGet);
            return responseHandler(httpGet, closeResponse);
        } catch (Exception e) {
            log.error("请求:[{}] 失败； 原因：{}", url, e);
        }
        return null;
    }

    /**
     * 处理返回的response请求, 返回String数据
     */
    private static String responseHandler(HttpRequestBase base, CloseableHttpResponse closeResponse) {
        String result = null;
        HttpEntity httpEntity = closeResponse.getEntity();
        try {
            if (httpEntity != null) {
                result = EntityUtils.toString(httpEntity);
            }
            log.info("请求: {}, 返回的数据为： {}", base.getURI(), result);
        } catch (Exception e) {
            log.error("请求: [{}]地址失败, 原因: {}", base.getURI(), e);
        } finally {
            if (closeResponse != null) {
                try {
                    closeResponse.close();
                } catch (IOException e) {
                    log.warn("{}的响应流关闭失败；原因: {}", base.getURI(), e);
                }
            }
        }
        return result;
    }

}
